11719. Уменьшить
массив
Задан массив, состоящий из n целых
чисел, и число k. Найдите минимальную стоимость сведения массива до
одного элемента. Вы можете выполнять следующую операцию любое количество раз:
·
Выберите любую пару соседних элементов ai и ai+1
и замените их на (ai + ai+1).
Стоимость такой операции равна k * (ai + ai+1).
Вход. Первая строка содержит два
натуральных числа n и k (n, k ≤
100). Вторая строка содержит n целых чисел a1,
a2, …, an (0 ≤ ai ≤
100).
Выход. Выведите минимальную стоимость
сведения массива до одного элемента.
Пример входа 1 |
Пример выхода 1 |
3 2 1 2 3 |
18 |
|
|
Пример входа 2 |
Пример выхода 2 |
4 3 4 5 6 7 |
132 |
динамическое
программирование
Пусть f(i, j) – минимальная стоимость, за которую
можно свести массив [ai,
…, aj] до одного элемента. Это значение будем хранить в
ячейке dp[i][j].
Очевидно, что f(i, i) = 0.
Из условия задачи следует, что
f(i, i + 1) = k * (ai + ai+1)
Вычислим
значение f(i, i + 2). Объединение трех чисел в одно можно
совершить двумя способами:
·
Объединить ai и ai+1 за k * (ai + ai+1), после чего объединить ai + ai+1 и ai+2 за k * (ai + ai+1 + ai+2).
·
Объединить ai+1 и ai+2 за k * (ai+1 + ai+2), после чего объединить ai и ai+1 + ai+2 за k * (ai + ai+1 + ai+2).
Таким образом f(i, i + 2) =
min(k * (ai + ai+1) + k * (ai
+ ai+1 + ai+2), k * (ai+1
+ ai+2) + k * (ai + ai+1
+ ai+2))
Теперь
рассмотрим вычисление значения f(i, j). Для преобразования массива [ai, …, aj] в один элемент, который будет
равен ai + …+ aj, следует выбрать некоторое
значение p (i ≤ p < j),
рекурсивно решить
задачу для массивов [ai,
…, ap] и [ap+1,
…, aj], после чего объединить элементы ai + … + ap и ap+1 + … + aj. Значение p следует выбрать таким образом, чтобы стоимость
преобразования была минимальной:
f(i, j) =
Для быстрых
вычислений сумм ai + …+ aj воспользуемся
массивом префиксных сумм pref, в котором
pref[i] = a1 + …+ ai,
откуда ai + …+ aj = pref[j] – pref[i – 1] .
Реализация алгоритма
Объявим
рабочие массивы.
#define MAX 101
#define INF 0x3F3F3F3F
int dp[MAX][MAX], a[MAX],
pref[MAX];
Функция f(i, j) возвращает минимальную стоимость, за которую
можно преобразовать массив [ai,
…, aj] к одному элементу.
int f(int i, int j)
{
if (dp[i][j] == INF)
for (int p = i; p
< j; p++)
dp[i][j] = min(dp[i][j], f(i, p) +
f(p + 1, j) +
(pref[j] - pref[i - 1])
* k);
return dp[i][j];
}
Основная часть программы. Читаем входные данные.
scanf("%d %d", &n, &k);
memset(dp,
0x3F, sizeof(dp));
for (i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
dp[i][i] = 0;
Вычисляем массив префиксных сумм.
pref[i] = pref[i - 1] + a[i];
}
Вычисляем и выводим ответ.
printf("%d\n", f(1, n));
Python реализация
Объявим
константу бесконечность.
INF = float('inf')
Функция f(i, j) возвращает минимальную стоимость, за которую
можно преобразовать массив [ai,
…, aj] к одному элементу.
def f(i, j):
if dp[i][j] == INF:
for p in range(i, j):
dp[i][j] = min(dp[i][j], f(i, p) + f(p + 1, j) +
(pref[j] - pref[i - 1]) * k)
return dp[i][j]
Основная часть программы. Читаем входные данные.
n, k = map(int, input().split())
a = [0] + list(map(int, input().split()))
Вычисляем массив префиксных сумм.
pref = [0] * (n + 1)
for i in range(1, n + 1):
pref[i] = pref[i - 1] + a[i]
Инициализируем массив dp.
dp = [[INF] * (n + 1) for
_ in range(n + 1)]
for i in range(1, n + 1):
dp[i][i] = 0
Вычисляем и выводим ответ.
print(f(1, n))